﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Sinacor.OMM.Router.ProcessEntity;
using Sinacor.OMM.Util;

namespace Sinacor.OMM.Router.ProcessLogic
{
    public class DictionaryOrderManager : IDisposable
    {
        private TraceWriter _traceWriter;
        private List<Order> _orders;
        private static DictionaryOrderManager _instance;        

        public int Count
        {
            get
            {
                int count = 0;
                lock (_orders)
                    count = _orders.Count;

                return count;
            }
        }

        private DictionaryOrderManager()
        {
            _traceWriter = Tracer.GetInstance("Roteador", "OrderDictionary.log");
            _orders = new List<Order>();            
            LoadOrders();
        }        

        public static DictionaryOrderManager GetInstance()
        {
            if (_instance == null)
                _instance = new DictionaryOrderManager();

            return _instance;
        }

        /// <summary>
        /// Adds an order to the manager.
        /// </summary>
        /// <param name="message"></param>
        public void AddOrder(MessageEntity.BaseMessage message)
        {
            lock (_orders)
                _orders.Add(TranslateToOrder(message));

            Trace();
        }

        /// <summary>
        /// Verifies if the specified order is already open.
        /// </summary>
        /// <param name="message"></param>
        /// <returns></returns>
        public bool Exists(MessageEntity.BaseMessage message)
        {
            Order order = TranslateToOrder(message);

            var count = (from o in _orders
                         where o.Client == order.Client &&
                         o.Operator == order.Operator &&
                         o.Stock.ToUpper().Trim() == order.Stock.ToUpper().Trim() &&
                         o.TradeSign.ToUpper().Trim() == order.TradeSign.ToUpper().Trim()
                         select o).Count();

            return (count > 0);
        }

        /// <summary>
        /// Translate a message object into a order object.
        /// </summary>
        /// <param name="message"></param>
        /// <returns></returns>
        public Order TranslateToOrder(MessageEntity.BaseMessage message)
        {
            MessageEntity.STM.Message0103 message0103;
            MessageEntity.STM.Message0105 message0105;
            MessageEntity.STM.Message0138 message0138;
            MessageEntity.STM.Message0172 message0172;
            Order order = null;

            if (message is MessageEntity.STM.Message0103)
            {
                message0103 = (MessageEntity.STM.Message0103)message;
                order = new Order() { Client = message0103.Client, Operator = message0103.Operator, Stock = message0103.Stock };

                switch (message0103.NaturezaOperacao)
                {
                    case Sinacor.OMM.MessageEntity.Enum.NaturezaOperacao.Compra:
                        order.TradeSign = "A";
                        break;
                    case Sinacor.OMM.MessageEntity.Enum.NaturezaOperacao.Venda:
                        order.TradeSign = "V";
                        break;
                }
            }

            if (message is MessageEntity.STM.Message0105)
            {
                message0105 = (MessageEntity.STM.Message0105)message;
                order = new Order() { Client = message0105.Client, Operator = message0105.Operator, Stock = message0105.Stock };

                switch (message0105.NaturezaOperacao)
                {
                    case Sinacor.OMM.MessageEntity.Enum.NaturezaOperacao.Compra:
                        order.TradeSign = "A";
                        break;
                    case Sinacor.OMM.MessageEntity.Enum.NaturezaOperacao.Venda:
                        order.TradeSign = "V";
                        break;
                }
            }

            if (message is MessageEntity.STM.Message0138)
            {
                message0138 = (MessageEntity.STM.Message0138)message;
                order = new Order() { Client = message0138.Client, Operator = message0138.Operator, Stock = message0138.Stock };

                switch (message0138.NaturezaOperacao)
                {
                    case Sinacor.OMM.MessageEntity.Enum.NaturezaOperacao.Compra:
                        order.TradeSign = "A";
                        break;
                    case Sinacor.OMM.MessageEntity.Enum.NaturezaOperacao.Venda:
                        order.TradeSign = "V";
                        break;
                }
            }

            if (message is MessageEntity.STM.Message0172)
            {
                message0172 = (MessageEntity.STM.Message0172)message;
                order = new Order() { Client = message0172.Client, Operator = message0172.Operator, Stock = message0172.Stock };

                switch (message0172.NaturezaOperacao)
                {
                    case Sinacor.OMM.MessageEntity.Enum.NaturezaOperacao.Compra:
                        order.TradeSign = "A";
                        break;
                    case Sinacor.OMM.MessageEntity.Enum.NaturezaOperacao.Venda:
                        order.TradeSign = "V";
                        break;
                }
            }

            return order;
        }

        /// <summary>
        /// Return orders 
        /// </summary>
        /// <returns></returns>
        public void LoadOrders()
        {
            List<Order> orders = new List<Order>();

            try
            {
                ResourceAccess.OrderManager ordMgr = new Sinacor.OMM.Router.ResourceAccess.OrderManager(RouterConfigurationManager.Authentication.CompanyId);
                orders = ordMgr.RetrieveOrders(RouterConfigurationManager.OrderBovespaSystemInformation.SystemDate);

                lock (_orders)
                {
                    _orders.Clear();
                    _orders = orders;
                }

                Trace();
            }
            catch (Exception ex)
            {
                _traceWriter.Trace("Error when trying to load dictionary's orders. " + string.Concat(ex.Message, " ", ex.StackTrace));
            }
        }

        private void Trace()
        {
            if (_orders != null)
            {
                lock (_orders)
                {
                    _traceWriter.Trace("Beginning");
                    foreach (var item in _orders)
                    {
                        _traceWriter.Trace(string.Format("Client: {0}, Operator: {1}, Stock: {2}, TradeSign: {3}", 
                            item.Client, item.Operator, item.Stock, item.TradeSign));
                    }
                    _traceWriter.Trace("End");
                }
            }
        }

        #region IDisposable Members

        public void Dispose()
        {
            _traceWriter = null;
        }

        #endregion
    }
}
